package org.example.trigger.http;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.example.api.response.Response;
import org.example.domain.config.PanSouProperties;
import org.example.domain.search.service.SearchService;
import org.example.types.model.SearchRequest;
import org.example.types.model.SearchResponse;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 搜索控制器
 */
@Slf4j
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class SearchController {

    private final SearchService searchService;
    private final PanSouProperties panSouProperties;

    /**
     * 搜索接口 - POST方式
     */
    @PostMapping("/search")
    public Mono<Response<SearchResponse>> searchPost(@RequestBody SearchRequest request) {
        return validateAndSearch(request);
    }

    /**
     * 搜索接口 - GET方式
     */
    @GetMapping("/search")
    public Mono<Response<SearchResponse>> searchGet(
            @RequestParam("kw") String keyword,
            @RequestParam(value = "channels", required = false) String channels,
            @RequestParam(value = "conc", required = false) Integer concurrency,
            @RequestParam(value = "refresh", required = false, defaultValue = "false") boolean forceRefresh,
            @RequestParam(value = "res", required = false, defaultValue = "merge") String resultType,
            @RequestParam(value = "src", required = false, defaultValue = "all") String sourceType,
            @RequestParam(value = "plugins", required = false) String plugins,
            @RequestParam(value = "cloud_types", required = false) String cloudTypes,
            @RequestParam(value = "ext", required = false) Map<String, Object> ext) {

        // 构建搜索请求
        SearchRequest request = SearchRequest.builder()
                .keyword(keyword)
                .channels(parseStringList(channels))
                .concurrency(concurrency)
                .forceRefresh(forceRefresh)
                .resultType(resultType)
                .sourceType(sourceType)
                .plugins(parseStringList(plugins))
                .cloudTypes(parseStringList(cloudTypes))
                .ext(ext)
                .build();

        return validateAndSearch(request);
    }

    /**
     * 验证并执行搜索
     */
    private Mono<Response<SearchResponse>> validateAndSearch(SearchRequest request) {
        // 验证请求参数
        String validationError = validateRequest(request);
        if (validationError != null) {
            return Mono.just(Response.<SearchResponse>builder()
                    .code("400")
                    .info(validationError)
                    .build());
        }

        // 设置默认值
        setDefaultValues(request);

        log.info("Search request: keyword={}, channels={}, plugins={}, sourceType={}",
                request.getKeyword(),
                request.getChannels(),
                request.getPlugins(),
                request.getSourceType());

        // 执行搜索
        return searchService.search(request)
                .map(searchResponse -> Response.<SearchResponse>builder()
                        .code("0000")
                        .info("success")
                        .data(searchResponse)
                        .build())
                .onErrorResume(ex -> {
                    log.error("Search failed for keyword: {}", request.getKeyword(), ex);
                    return Mono.just(Response.<SearchResponse>builder()
                            .code("500")
                            .info("搜索失败: " + ex.getMessage())
                            .build());
                });
    }

    /**
     * 验证请求参数
     */
    private String validateRequest(SearchRequest request) {
        if (StringUtils.isBlank(request.getKeyword())) {
            return "关键词不能为空";
        }

        if (request.getKeyword().length() > 100) {
            return "关键词长度不能超过100个字符";
        }

        if (request.getConcurrency() != null && (request.getConcurrency() < 1 || request.getConcurrency() > 100)) {
            return "并发数必须在1-100之间";
        }

        return null;
    }

    /**
     * 设置默认值
     */
    private void setDefaultValues(SearchRequest request) {
        // 设置默认频道
        if (request.getChannels() == null || request.getChannels().isEmpty()) {
            request.setChannels(panSouProperties.getDefaultChannels());
        }

        // 设置默认并发数
        if (request.getConcurrency() == null || request.getConcurrency() <= 0) {
            request.setConcurrency(panSouProperties.getDefaultConcurrency());
        }

        // 设置默认结果类型
        if (StringUtils.isBlank(request.getResultType())) {
            request.setResultType("merge");
        } else if ("merge".equals(request.getResultType())) {
            request.setResultType("merged_by_type");
        }

        // 设置默认来源类型
        if (StringUtils.isBlank(request.getSourceType())) {
            request.setSourceType("all");
        }

        // 参数互斥逻辑
        if ("tg".equals(request.getSourceType())) {
            request.setPlugins(null); // 忽略plugins参数
        } else if ("plugin".equals(request.getSourceType())) {
            request.setChannels(null); // 忽略channels参数
        }
    }

    /**
     * 解析逗号分隔的字符串列表
     */
    private List<String> parseStringList(String str) {
        if (StringUtils.isBlank(str)) {
            return null;
        }
        return Arrays.stream(str.split(","))
                .map(String::trim)
                .filter(StringUtils::isNotBlank)
                .toList();
    }

    /**
     * 健康检查接口
     */
    @GetMapping("/health")
    public Mono<Response<Map<String, Object>>> health() {
        // TODO: 实现健康检查逻辑
        Map<String, Object> healthData = Map.of(
                "status", "ok",
                "timestamp", System.currentTimeMillis()
        );

        return Mono.just(Response.<Map<String, Object>>builder()
                .code("0000")
                .info("success")
                .data(healthData)
                .build());
    }
}